//
//  IFlySynthesis.m
//  Learn
//
//  Created by cjg.mini on 2024/4/8.
//  Copyright © 2024 迟建国. All rights reserved.
//

#import "IFlySynthesis.h"
#import <QuartzCore/QuartzCore.h>
#import <AVFoundation/AVAudioSession.h>
#import <AudioToolbox/AudioSession.h>
#import "Definition.h"
#import "TTSConfig.h"

@interface IFlySynthesis () <IFlySpeechSynthesizerDelegate>

@end

@implementation IFlySynthesis

- (instancetype)init {
    if (self = [super init]) {
        [self settingForTTS];
        [self initSynthesizer];

    }
    return self;
}

-(void)dealloc {
    self.isViewDidDisappear = true;
    [_iFlySpeechSynthesizer stopSpeaking];
    [_audioPlayer stop];
    _iFlySpeechSynthesizer.delegate = nil;
}

- (void)startNomalSynthesisWith:(NSString *)text {
    
    if (_audioPlayer != nil && _audioPlayer.isPlaying == YES) {
        [_audioPlayer stop];
    }
    
    _synType = NomalType;
    
    self.hasError = NO;
    [NSThread sleepForTimeInterval:0.05];
    
    self.isCanceled = NO;

    _iFlySpeechSynthesizer.delegate = self;
    
    
    [_iFlySpeechSynthesizer startSpeaking:text];
    if (_iFlySpeechSynthesizer.isSpeaking) {
        _state = Playing;
    }
}

- (void)startURISynthesisWith:(NSString *)text {
    if (_audioPlayer != nil && _audioPlayer.isPlaying == YES) {
        [_audioPlayer stop];
    }
    
    _synType = UriType;
    
    self.hasError = NO;
    
    [NSThread sleepForTimeInterval:0.05];

    
    
    self.isCanceled = NO;
    
    _iFlySpeechSynthesizer.delegate = self;
    
    [_iFlySpeechSynthesizer synthesize:text toUri:_uriPath];
    if (_iFlySpeechSynthesizer.isSpeaking) {
        _state = Playing;
    }

}


/**
 cancel TTS
 Notice：
 1、cancel TTS and stop player for normal TTS；
 2、cancel TTS but storage the saved audio pcm data for URI TTS；
 **/
- (void)cancel {
    [_iFlySpeechSynthesizer stopSpeaking];
}

/**
 pause player
 Notice：
    Only apply to normal TTS
 **/
- (void)pause {
    [_iFlySpeechSynthesizer pauseSpeaking];
}

/**
 resume palyer
 Notice：
    Only apply to normal TTS
 **/
- (void)resume {
    [_iFlySpeechSynthesizer resumeSpeaking];
}


#pragma mark - IFlySpeechSynthesizerDelegate

/**
 callback of starting playing
 Notice：
    Only apply to normal TTS
 **/
- (void)onSpeakBegin
{
    self.isCanceled = NO;
    if (_state  != Playing) {
    }
    _state = Playing;
    if (self.delegate && [self.delegate respondsToSelector:@selector(onSpeakBegin)]) {
        [self.delegate onSpeakBegin];
    }
}

/**
 callback of buffer progress
 Notice：
    Only apply to normal TTS
 **/
- (void)onBufferProgress:(int) progress message:(NSString *)msg
{
    DebugLog(@"buffer progress %2d%%. msg: %@.", progress, msg);
    if (self.delegate && [self.delegate respondsToSelector:@selector(onBufferProgress: message:)]) {
        [self.delegate onBufferProgress:progress message:msg];
    }
}

/**
 callback of playback progress
 Notice：
    Only apply to normal TTS
 **/
- (void) onSpeakProgress:(int) progress beginPos:(int)beginPos endPos:(int)endPos
{
    DebugLog(@"speak progress %2d%%, beginPos=%d, endPos=%d", progress,beginPos,endPos);
    if (self.delegate && [self.delegate respondsToSelector:@selector(onSpeakProgress: beginPos: endPos:)]) {
        [self.delegate onSpeakProgress:progress beginPos:beginPos endPos:endPos];
    }
}

/**
 callback of pausing player
 Notice：
    Only apply to normal TTS
 **/
- (void)onSpeakPaused
{
    _state = Paused;
    if (self.delegate && [self.delegate respondsToSelector:@selector(onSpeakPaused)]) {
        [self.delegate onSpeakPaused];
    }
}

/**
 callback of TTS completion
 **/
- (void)onCompleted:(IFlySpeechError *) error
{
    if (self.delegate && [self.delegate respondsToSelector:@selector(onCompleted:)]) {
        [self.delegate onCompleted:error];
    }

    DebugLog(@"%s,error=%d",__func__,error.errorCode);
    
    if (error.errorCode ==10102) {
        
        DebugLog(@"%s,errorCode:%d",__func__,error.errorCode);
    }
    if (error.errorCode != 0) {
        if(error.errorCode==10102){
            DebugLog(@"%s,errorCode:%d",__func__,error.errorCode);
        }else{
        }
        return;
    }
   
    NSString *text ;
    if (self.isCanceled) {
        text = NSLocalizedString(@"T_TTS_Cancel", nil);
    }else if (error.errorCode == 0) {
        text = NSLocalizedString(@"T_TTS_End", nil);
    }else {
        text = [NSString stringWithFormat:@"Error：%d %@",error.errorCode,error.errorDesc];
        self.hasError = YES;
        DebugLog(@"%@",text);
    }
        
    _state = NotStart;
    
    if (_synType == UriType) {//URI TTS
        NSFileManager *fm = [NSFileManager defaultManager];
        if ([fm fileExistsAtPath:_uriPath]) {
            [self playUriAudio];//play the audio file generated by URI TTS
        }
    }
}

#pragma mark - Setting For URI TTS
- (void)settingForTTS {
    
    //URI TTS: -(void)synthesize:(NSString *)text toUri:(NSString*)uri
    //If uri is nil, the audio file is saved in library/cache by defailt.
    NSString *prePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    //Set the audio file name for URI TTS
    _uriPath = [NSString stringWithFormat:@"%@/%@",prePath,@"uri.pcm"];
    //Instantiate player for URI TTS
    _audioPlayer = [[PcmPlayer alloc] init];

}
#pragma mark - Initialization

- (void)initSynthesizer
{
    TTSConfig *instance = [TTSConfig sharedInstance];
    if (instance == nil) {
        return;
    }
    
    //TTS singleton
    if (_iFlySpeechSynthesizer == nil) {
        _iFlySpeechSynthesizer = [IFlySpeechSynthesizer sharedInstance];
    }
    
    _iFlySpeechSynthesizer.delegate = self;
    
    [_iFlySpeechSynthesizer setParameter:@"" forKey:[IFlySpeechConstant PARAMS]];
    
    //set the resource path, only for offline TTS
    NSString *resPath = [[NSBundle mainBundle] resourcePath];
    NSString *newResPath = [[NSString alloc] initWithFormat:@"%@/xtts/purextts_common.jet;%@/xtts/purextts_xiaoyan.jet",resPath,resPath];

    [[IFlySpeechUtility getUtility] setParameter:@"tts" forKey:[IFlyResourceUtil ENGINE_START]];
    
    [_iFlySpeechSynthesizer setParameter:newResPath forKey:@"tts_res_path"];
    
    //set speed,range from 1 to 100.
    [_iFlySpeechSynthesizer setParameter:instance.speed forKey:[IFlySpeechConstant SPEED]];

    //set volume,range from 1 to 100.
    [_iFlySpeechSynthesizer setParameter:instance.volume forKey:[IFlySpeechConstant VOLUME]];

    //set pitch,range from 1 to 100.
    [_iFlySpeechSynthesizer setParameter:instance.pitch forKey:[IFlySpeechConstant PITCH]];

    //set sample rate
    [_iFlySpeechSynthesizer setParameter:instance.sampleRate forKey:[IFlySpeechConstant SAMPLE_RATE]];

    //set TTS speaker
    [_iFlySpeechSynthesizer setParameter:instance.vcnName forKey:[IFlySpeechConstant VOICE_NAME]];
    DebugLog(@"发音人：%@",instance.vcnName);
    
    [_iFlySpeechSynthesizer setParameter:@"unicode" forKey:[IFlySpeechConstant TEXT_ENCODING]];
    
    [_iFlySpeechSynthesizer setParameter:instance.engineType forKey:[IFlySpeechConstant ENGINE_TYPE]];
    
    //set xtts params
    [_iFlySpeechSynthesizer setParameter:@"1" forKey:@"rdn"];
    [_iFlySpeechSynthesizer setParameter:@"0" forKey:@"effect"];
    [_iFlySpeechSynthesizer setParameter:@"0" forKey:@"rcn"];
    
    
    //set engine type
    [_iFlySpeechSynthesizer setParameter:instance.engineType forKey:[IFlySpeechConstant ENGINE_TYPE]];
    
    NSDictionary* languageDic=@{@"catherine":@"text_english",//English
                                @"XiaoYun":@"text_vietnam",//Vietnamese
                                @"Abha":@"text_hindi",//Hindi
                                @"Gabriela":@"text_spanish",//Spanish
                                @"Allabent":@"text_russian",//Russian
                                @"Mariane":@"text_french"};//French
    
    NSString* textNameKey=[languageDic valueForKey:instance.vcnName];
    NSString* textSample=nil;
    
    if(textNameKey && [textNameKey length]>0){
        textSample=NSLocalizedStringFromTable(textNameKey, @"tts/tts", nil);
    }else{
        textSample=NSLocalizedStringFromTable(@"text_chinese", @"tts/tts", nil);
    }

//    [_textView setText:textSample];

}

#pragma mark - Playing For URI TTS

- (void)playUriAudio
{
    TTSConfig *instance = [TTSConfig sharedInstance];
    NSError *error = nil;
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
    _audioPlayer = [[PcmPlayer alloc] initWithFilePath:_uriPath sampleRate:[instance.sampleRate integerValue]];
    [_audioPlayer play];
    
}

@end
